// Created by Laurent Mignonneau
// Advanced course example
// May 2011

// works with a 7x5 dot matrix display

// columns and rows are connected as follows
byte col[5] = {2, 3, 4, 5, 6};
byte row[7] = {7, 8, 9, 10, 11, 12, 13};

// six motifs is the original render view
byte motif[5][7]={   
   {1, 0, 0, 0, 0, 0, 1},
   {1, 0, 0, 0, 0, 0, 1},
   {1, 0, 0, 0, 1, 1, 1},
   {1, 0, 0, 0, 0, 0, 1},
   {1, 0, 0, 0, 0, 0, 1}};

byte car[2][3] = {
  {0, 1, 0},
  {1, 1, 1}};
int carLife = 4;
int carX = 1;
int carY = 4;


int raceTrack_height = 61;
int raceTrack_width = 5;
// Store the racetrack
byte racetrack [61][5]=  {
   {1, 1, 1, 1, 1},
   {1, 0, 0, 0, 1},
   {1, 0, 0, 0, 1},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 1},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {1, 0, 0, 0, 0},
   {1, 1, 0, 0, 0},
   {1, 1, 0, 0, 1},
   {1, 0, 0, 0, 1},
   {1, 1, 1, 1, 1} 
};

long previousMillis = 0; 
long interval = 50;
int frameCounter = 0;
 
int cameraPos = raceTrack_height -7; 
int index;
boolean debug = true;

void setup() {                
  // initialize the digital pin as outputs.
  pinMode(2, OUTPUT);     
  pinMode(3, OUTPUT);     
  pinMode(4, OUTPUT);     
  pinMode(5, OUTPUT);     
  pinMode(6, OUTPUT);     
  pinMode(7, OUTPUT);     
  pinMode(8, OUTPUT);     
  pinMode(9, OUTPUT);     
  pinMode(10, OUTPUT);     
  pinMode(11, OUTPUT);     
  pinMode(12, OUTPUT);     
  
  
  // only one col at a time (here LOW means that the column is making the row LEDs visible !)
  digitalWrite(2, HIGH);   // set col LED off
  digitalWrite(3, HIGH);   // set col LED off
  digitalWrite(4, HIGH);   // set col LED off
  digitalWrite(5, HIGH);   // set col LED off
  digitalWrite(6, HIGH);   // set col LED off

  // 7 pixels visible in one col
  digitalWrite(7, HIGH);   // set the LED on
  digitalWrite(8, HIGH);   // set the LED on
  digitalWrite(9, HIGH);   // set the LED on
  digitalWrite(10, HIGH);   // set the LED on
  digitalWrite(11, HIGH);   // set the LED on
  digitalWrite(12, HIGH);   // set the LED on
  digitalWrite(13, HIGH);   // set the LED on
  
  Serial.begin(9600);

}

void loop() {
  
  ////////////////////////////////////////////////
  // Game Logic
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis; 
    frameCounter++;
    
    
    if(cameraPos <= 0)
    {
      // Game Finished
    } else {
      
       // Moving the screen
       if(frameCounter > 5) {
         frameCounter = 0;
         cameraPos--;
       }
    }
    if(debug) Serial.println(cameraPos);
  } // End Timer intervall
  
  
  ////////////////////////////////////////////////
  // Map the game data to the screen
  render();
  // Render the data directly for the hardware
  renderHardware();
  
  
}

void render() 
{
  int gameY,gameX;
  int targetX = 6;
  int targetY = 0;
  char value;
  
  //if(debug) Serial.println("-----------------");
  //if(debug) Serial.println("");
  for(gameY=0;gameY<7;gameY++)
  {
    for(gameX=0;gameX<5;gameX++)
    {
      motif[targetY][targetX] = racetrack[6+cameraPos-gameY][gameX];
      
      if(motif[targetY][targetX] > 0)
        value = '1';
      else
        value = '0';
  
      //if(debug) Serial.print(value);
      targetY++;
    }
    targetY = 0;
    targetX--;
    
    //if(debug) Serial.println("");
  } 
  
  /* For Debugging Trace the display renderer
  if(debug)
  {
    Serial.println("--- Hardware Display --");
    Serial.println("");
    for(int k = 0; k<5;k++) {
      for(int l = 0; l<7;l++) {
        if(motif[k][l] > 0)
          value = '1';
        else
          value = '0';
        
        Serial.print(value);
      }
      Serial.println("");
    }
  }*/
  debug = true;
}

void renderHardware()
{
  //////////////////////////////////////////////////////////////////////////////////////////////////
  // display the Game Graphic on the Hardware Screen
  int cl;
  // each column is scanned one at a time
  for(cl=0; cl < 5; cl++)
  { 
     //turn ON the selected column first
     digitalWrite(col[cl], LOW);
     // then find out if each pixel is ON or OFF in the row
     for(index=0;index<7;index++)
     {
       if(motif[cl][index] < 1) digitalWrite(row[index], LOW);
       else digitalWrite(row[index], HIGH);
     }
     // slows down the loop a bit to get more light output.
     // if you need to read sensors, you can do it here instead this delay

     //Serial.println(analogRead(A0));
     //Serial.println(scrollingPos = analogRead(A0) / 16);
     delay(1);
     // now turn OFF the current column
     digitalWrite(col[cl], HIGH);
     // well, that's it
     
  } 
}

